/**
 *
 */


var DEBUG = true;


/* ------------------------ Setup and initialization functions ---------- */


/**
 * Entry function for adding the calculator to a specified container.
 * 
 * Creates the controls for the calculator inside containerId and sets up the
 * listener functions
 */
function initDestockCalculator(containerId) {
  if(!checkContainerId(containerId))
    return;
  
  addStyleElement();
  addHTML(containerId);
  setListenerFunctions();
}

function checkContainerId(containerId) {
  var containerElem = document.getElementById(containerId);
  if(!containerElem) {
    if(DEBUG)
      alert("container with id '" + containerId + "' not found");
    return false;
  }
  return true;
}

function addHTML(containerId) {
  var outerContainer = document.getElementById(containerId);
  var container = document.createElement("div");
  container.id = "destock_container";
  container.innerHTML = destock_html;
  outerContainer.appendChild(container);
}

function addStyleElement() {
  var styleElem = document.createElement("style");
  styleElem.innerHTML = destock_css;
  document.getElementsByTagName("head")[0].appendChild(styleElem);
}

function setListenerFunctions() {
  var inputControls = [ "input_gov", "input_land", "input_cs", "input_mb_current",
    "input_mb_to_build", "input_miltech_amt", "input_miltech_to_buy", "input_miltech_price",
    "input_bonus_build", "input_bonus_pm",
    "input_stock", "input_sellprice"];
  for( id in inputControls ) {
    document.getElementById(inputControls[id]).onchange = startCalculations;
  }
}


/* -------------------------- Calculation variables --------------- */

var government;
var land;
var construction_sites;
var mil_bases;
var mil_bases_to_build;
var miltech_amt;
var miltech_to_buy;
var miltech_price;
var bonus_build;
var bonus_pm;
var stock_amt;
var sell_price;

var taxrate;
var gov_build_bonus;
var gov_pm_bonus;

var bpt;
var reconstruction_cost;
var miltech;
var miltech_cost;
var troop_price;
var jet_price;
var turret_price;
var tank_price;
var troop_amt;
var jet_amt;
var turret_amt;
var tank_amt;

var buyout_cost;
var total_to_spend;
var buyout_time;


function resetVariables() {
  government = null;
  land = null;
  construction_sites = null;
  mil_bases = null;
  mil_bases_to_build = null;
  miltech_amt = null;
  miltech_to_buy = null;
  miltech_price = null;
  bonus_build = null;
  bonus_pm = null;
  stock_amt = null;
  sell_price = null;
  
  taxrate = 0.06;
  gov_build_bonus = 1;
  gov_pm_bonus = 1;

  bpt = null;
  reconstruction_cost = null;
  miltech = null;
  miltech_cost = null;
  troop_price = null;
  jet_price = null;
  turret_price = null;
  tank_price = null;
  troop_amt = null;
  jet_amt = null;
  turret_amt = null;
  tank_amt = null;
  
  buyout_cost = null;
  total_to_spend = null;
  buyout_time = null;
}


/* ---------------------------- Calculation functions ----------------- */

function startCalculations() {
  resetOutputs();
  resetVariables();
  readInputs();
  
  setGovernmentBonuses();
  
  calcBPT();
  calcReconstructionCosts();
  calcReconstructionTime();
  
  calcMilitaryTech();
  calcUnitPrices();
  calcPMReplenishment();
  calcBuyout();
  calcStockWorth();
  calcStockNetworth();
}

function calcBPT() {
  if(construction_sites == null)
    return;
  
  bpt = Math.floor( ( construction_sites / 4 + 5 ) * gov_build_bonus );
  setOutput("output_bpt", bpt);
}

function calcReconstructionCosts() {
  if(!land || mil_bases_to_build == null)
    return;
  
  var construction_cost = (1+bonus_build/100) * (3*land + 1500);
  var destruction_cost = Math.ceil( 0.2 * construction_cost );
  reconstruction_cost = mil_bases_to_build * (construction_cost+destruction_cost);
  setOutput("output_ccosts", fmtMoney(reconstruction_cost));
}

function calcReconstructionTime() {
  if(!bpt || mil_bases_to_build == null)
    return;
  
  var reconstruction_time_turns = Math.ceil(mil_bases_to_build/bpt);
  setOutput("output_cturns", fmtTurns(reconstruction_time_turns) );
}

function calcMilitaryTech() {
  if( land == null || miltech_amt == null || miltech_to_buy == null || miltech_price == null )
    return;
  // Tech% = BaseTech%+(MaxTech%-BaseTech%)*GvtTech*(1-EXP(-GvtEff*TechPts/(C1+C2*Land)))
  var basetech = 100;
  var maxtech = maxMilTech();
  var gvttech = govTech();
  var gvteff  = 1;
  var techpts = miltech_amt + miltech_to_buy;
  
  miltech = basetech + (maxtech-basetech)*gvttech*(1-Math.exp(-gvteff*techpts/(780+5.75*land)));
  setOutput("output_miltech", fmtFloat(miltech) + "%");
  
  miltech_cost = miltech_to_buy * miltech_price * (1+taxrate);
  setOutput("output_miltech_cost", fmtMoney(miltech_cost));
}

function maxMilTech() {
  //if(government == "theo")
  //  return 89.16;
  //if(government == "demo")
  //  return 81.66;
  return 500/6;
}

function govTech() {
  if(government == "theo")
    return 0.65;
  if(government == "demo")
    return 1.1;
  return 1;
}

function calcUnitPrices() {
  if(land == null || mil_bases == null || mil_bases_to_build == null || miltech == null)
    return;
  
  troop_price  = privateMarketAdjustedPrice(144);
  jet_price    = privateMarketAdjustedPrice(192);
  turret_price = privateMarketAdjustedPrice(210);
  tank_price   = privateMarketAdjustedPrice(588);
}

function privateMarketAdjustedPrice(basePrice) {
  var price = basePrice * gov_pm_bonus * (miltech/100);
  if(mil_bases + mil_bases_to_build > 0)
    price = price * ( 1 - 0.25 * ((mil_bases+mil_bases_to_build)/land) );
  return Math.round(price);
}

function calcPMReplenishment() {
  if(!land)
    return;
  
  troop_amt = replenishmentPerTurn(3);
  turret_amt = replenishmentPerTurn(2.5);
  jet_amt = replenishmentPerTurn(2.5);
  tank_amt = replenishmentPerTurn(1);
  
  setOutput("output_unitprice_troops", fmtMoney(troop_price) + " (" + fmtNumber(troop_amt) + ")" );
  setOutput("output_unitprice_jets", fmtMoney(jet_price) + " (" + fmtNumber(jet_amt) + ")" );
  setOutput("output_unitprice_turrets", fmtMoney(turret_price) + " (" + fmtNumber(turret_amt) + ")" );
  setOutput("output_unitprice_tanks", fmtMoney(tank_price) + " (" + fmtNumber(tank_amt) + ")" );
}

function replenishmentPerTurn(unitRate) {
  return (1+bonus_pm/100) * unitRate * land;
}

function calcBuyout() {
  if(!troop_price)
    return;
  
  buyout_cost = 
    troop_amt * troop_price +
    jet_amt * jet_price +
    turret_amt * turret_price +
    tank_amt * tank_price;
  setOutput("output_buyout_cost", fmtMoney(buyout_cost));
}

function calcStockWorth() {
  if(stock_amt == null || sell_price == null)
    return;
  
  var worth = stock_amt * 1000000 * sell_price * (1-taxrate);
  setOutput("output_stock_revenue", fmtMoney(worth));
  
  total_to_spend = worth - reconstruction_cost - miltech_cost;
  setOutput("output_total_to_spend", fmtMoney(total_to_spend));
  
  buyout_time = Math.ceil(total_to_spend / buyout_cost);
  setOutput("output_buyout_time", fmtTurns(buyout_time));
}

function calcStockNetworth() {
  var total_nw = buyout_time * (
    ( troop_amt * 0.5 ) +
    ( jet_amt * 0.6 ) + 
    ( turret_amt * 0.6 ) +
    ( tank_amt * 2 )
  );
  setOutput("output_est_nw", fmtMoney(total_nw));
}

function setGovernmentBonuses() {
  if(government == "theo")
    setTheoBonuses();
  else if(government == "demo")
    setDemoBonuses();
}

function setTheoBonuses() {
  gov_build_bonus = 1.4;
  gov_pm_bonus = 0.8;
}

function setDemoBonuses() {
  taxrate = 0;
}

/* ---------------------- Read and verify functions ----------------- */

function readInputs() {
  readGovernment();
  
  land = readIntInput("input_land", "err_land");
  construction_sites = readIntInput("input_cs", "err_cs");
  mil_bases = readIntInput("input_mb_current", "err_mbc");
  mil_bases_to_build = readIntInput("input_mb_to_build", "err_mbb");
  
  miltech_amt = readIntInput("input_miltech_amt", "err_milt");
  miltech_to_buy = readIntInput("input_miltech_to_buy", "err_milt_b");
  miltech_price = readIntInput("input_miltech_price", "err_milt_p");
  
  bonus_build = readFloatInput("input_bonus_build", "err_bb");
  bonus_pm = readFloatInput("input_bonus_pm", "err_bp");
  stock_amt = readFloatInput("input_stock", "err_stock");
  sell_price = readIntInput("input_sellprice", "err_sell");
}

function readGovernment() {
  var govselect = document.getElementById("input_gov");
  government = govselect.value;
}

function readIntInput(input_elem, err_elem) {
  if(!hasValidInteger(input_elem)) {
    setErrorStatus(err_elem, true);
    return null;
  }
  setErrorStatus(err_elem, false);
  return getInteger(input_elem);
}

function readFloatInput(input_elem, err_elem) {
  if(!hasValidFloat(input_elem)) {
    setErrorStatus(err_elem, true);
    return null;
  }
  setErrorStatus(err_elem, false);
  return getFloat(input_elem);
}

/* ------------------------- Interaction helper functions ---------------- */

function resetOutputs() {
  var elems = [ "output_bpt", "output_ccosts", "output_cturns",
    "output_miltech", "output_miltech_cost",
    "output_unitprice_troops", "output_unitprice_jets", "output_unitprice_turrets",
    "output_unitprice_tanks", "output_buyout_cost", "output_stock_revenue",
    "output_total_to_spend", "output_buyout_time", "output_est_nw" ];
  for(var e in elems)
    document.getElementById(elems[e]).innerHTML = "";
}

function stripOptionalCommas(str) {
  return str.replace(",","");
}

// assumes positive integer input
function hasValidInteger(inputId) {
  var inputElem = document.getElementById(inputId);
  if(!inputElem) {
    alert("input with id '" + inputId + "' not found");
    return false;
  }
  var str = stripOptionalCommas(inputElem.value);
  var intVal = parseInt(str);
  if(str.length != (""+intVal).length) {
    return false;
  }
  return true;
}

function hasValidFloat(inputId) {
  var inputElem = document.getElementById(inputId);
  if(!inputElem) {
    alert("input with id '" + inputId + "' not found");
    return false;
  }
  var str = inputElem.value.replace("%", "").replace(",",".");
  var floatVal = parseFloat(str);
  if(str.length != (""+floatVal).length) {
    return false;
  }
  return true;
}

function getInteger(inputId) {
  var inputElem = document.getElementById(inputId);
  var str = stripOptionalCommas(inputElem.value);
  return parseInt(str);
}

function getFloat(inputId) {
  var inputElem = document.getElementById(inputId);
  var str = inputElem.value.replace("%", "").replace(",",".");
  return parseFloat(str);
}

function setErrorStatus(errDispId, isError) {
  var errElem = document.getElementById(errDispId);
  errElem.className = isError ? "failure" : "success";
}

function setOutput(dispId, val) {
  var e = document.getElementById(dispId);
  if(!e) {
    alert("output with id '" + dispId + "' not found");
    return;
  }
  e.innerHTML = val;
}

function fmtNumber(amt) {
  var numstr = "" + Math.floor(amt);
  var str = "";
  for(var i = numstr.length; i > 0; i--) {
    str = "" + numstr[i-1] + str;
    
    var j = numstr.length-i + 1;
    if(j != 0 && i != 1 && j%3/3 == 0)
      str = "," + str;
  }
  return str;
}

function fmtMoney(amt) {
  return "$ " + fmtNumber(amt);
}

function fmtTurns(turns) {
  return "" + turns + " (" + turnsToTimeString(turns) + ")";
}

// TODO Add settings field so the user can input the number of turns per hour
function turnsToTimeString(numTurns) {
  var numDays = numTurns / 72;
  var int = numDays - numDays % 1;
  var fraction = numDays % 1;
  
  var str = "" + int;
  if(fraction > 0)
    str = str + "." + (""+fraction).substr(2,1);
  
  return str + " days";
}

function fmtFloat(num) {
  var v = Math.abs(num);
  var int = v - v % 1;
  var fraction = v % 1;
  
  var str = (num < 0) ? "-" : "";
  str += fmtNumber(int);
  if(fraction > 0)
    str += "." + (""+fraction).substr(2,1);
  
  return str;
}

/* -------------------------------- HTML content ----------------------- */

var destock_css = '\
#destock_calculator {\
  width: 80%;\
  margin-left: auto;\
  margin-right: auto;\
}\
#input_controls {\
  float: left;\
  width: 48%;\
  margin-left: 1%;\
  margin-right: 1%;\
}\
#input_controls table {\
  width: 99%;\
}\
#input_controls table, #input_controls input, #input_controls select, #calc_results table {\
  font-size: 0.85em;\
}\
#calc_results {\
  width: 48%;\
}\
#calc_results table {\
  width: 99%;\
}\
td.head {\
  background-color: #8BB300;\
  font-size: 1.2em;\
}\
td.subhead {\
  background-color: #BFF500;\
  font-size: 1em;\
}\
div.success, div.failure {\
  height: 1em;\
  width: 1em;\
}\
div.success { background-color: #80FF80; }\
div.failure { background-color: #FF8080; }\
';

var destock_html = '\
  <h1>Destock calculator</h1>\
  <div id=input_controls>\
    <table>\
      <tr><td class="head" colspan="3">Inputs</td></tr>\
      <tr><td class="subhead" colspan="3">General</td></tr>\
      <tr>\
        <td>Government</td>\
	<td>\
	  <select id="input_gov">\
	    <option value="theo">Theocracy</option>\
	    <option value="demo">Democracy</option>\
	    <option value="other">Other</option>\
	  </select>\
	</td>\
      </tr>\
      <tr><td>Land</td><td><input type="text" id="input_land" /></td><td><div id="err_land" class="success" /></td></tr>\
      <tr><td>Constr. sites</td><td><input type="text" id="input_cs" /></td><td><div id="err_cs" class="success" /></td></tr>\
      <tr><td>Mil.Bases</td><td><input type="text" id="input_mb_current" /></td><td><div id="err_mbc" class="success" /></td></tr>\
      <tr><td>MBs to build</td><td><input type="text" id="input_mb_to_build" /></td><td><div id="err_mbb" class="success" /></td></tr>\
      <tr><td class="subhead" colspan="3">Military Tech</td></tr>\
      <tr><td>Mil.Tech amt</td><td><input type="text" id="input_miltech_amt" /></td><td><div id="err_milt" class="success" /></td></tr>\
      <tr><td>Mil.Tech to buy</td><td><input type="text" id="input_miltech_to_buy" /></td><td><div id="err_milt_b" class="success" /></td></tr>\
      <tr><td>avg price</td><td><input type="text" id="input_miltech_price" /></td><td><div id="err_milt_p" class="success" /></td></tr>\
      <tr><td class="subhead" colspan="3">Bonus</td></tr>\
      <tr><td>Build cost bonus</td><td><input type="text" id="input_bonus_build" /></td><td><div id="err_bb" class="success" /></td></tr>\
      <tr><td>Priv. Market bonus</td><td><input type="text" id="input_bonus_pm" /></td><td><div id="err_bp" class="success" /></td></tr>\
      <tr><td class="subhead" colspan="3">Stock</td></tr>\
      <tr><td>Stock (millions)</td><td><input type="text" id="input_stock" /></td><td><div id="err_stock" class="success" /></td></tr>\
      <tr><td>Avg. sell price</td><td><input type="text" id="input_sellprice" /></td><td><div id="err_sell" class="success" /></td></tr>\
    </table>\
  </div>\
  <div id="calc_results">\
    <table>\
      <tr><td class="head" colspan="2">Outputs</td></tr>\
      <tr><td class="subhead" colspan="2">Build</td></tr>\
      <tr><td>BPT</td><td><div id="output_bpt"></div></td></tr>\
      <tr><td>Reconstr. cost</td><td><div id="output_ccosts"></div></td></tr>\
      <tr><td>Reconstr. time</td><td><div id="output_cturns"></div></td></tr>\
      <tr><td class="subhead" colspan="2">Tech</td></tr>\
      <tr><td>Mil. Tech %</td><td><div id="output_miltech"></div></td></tr>\
      <tr><td>Add. tech costs</td><td><div id="output_miltech_cost"></div></td></tr>\
      <tr><td class="subhead" colspan="2">Unit-costs</td></tr>\
      <tr><td>Troops</td><td><div id="output_unitprice_troops"></div></td></tr>\
      <tr><td>Jets</td><td><div id="output_unitprice_jets"></div></td></tr>\
      <tr><td>Turrets</td><td><div id="output_unitprice_turrets"></div></td></tr>\
      <tr><td>Tanks</td><td><div id="output_unitprice_tanks"></div></td></tr>\
      <tr><td class="subhead" colspan="2">Buying/selling</td></tr>\
      <tr><td>Buyout/turn</td><td><div id="output_buyout_cost"></div></td></tr>\
      <tr><td>Stock-revenue</td><td><div id="output_stock_revenue"></div></td></tr>\
      <tr><td>Money to spend</td><td><div id="output_total_to_spend"></div></td></tr>\
      <tr><td>Buyout time</td><td><div id="output_buyout_time"></div></td></tr>\
      <tr><td>Est. nw</td><td><div id="output_est_nw"></div></td></tr>\
    </table>\
  </div>';
